package com.sy.nio.c1;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

import static com.sy.nio.c1.ByteBufferUtil.debugAll;

/**
 * @Author yumax
 * @Date 2024 01 04 09 44
 **/
@Slf4j
public class Server4 {

    public static void main(String[] args) throws IOException {
        //创建Selector，管理多个channel
        final Selector selector = Selector.open();
        final ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);//设置非阻塞模式

        //建立Selector和channel的联系（注册）
        //selectorKey就是将来事件发生后，知道哪个channel的事件
        final SelectionKey sscKey = ssc.register(selector, 0, null);
        //key只关注accept事件
        sscKey.interestOps(SelectionKey.OP_ACCEPT);

        ssc.bind(new InetSocketAddress(8989));

        while (true) {
            //select方法，没有事件发生，线程阻塞，有事件，线程才会恢复运行
            //select 在事件未处理时，它不会阻塞，事件发生后要么处理，要么取消，不能置之不理
            selector.select();

            //处理事件 selectedKeys内部包含了所有发生的事件
            final Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                final SelectionKey key = iterator.next();
                log.debug("key .. {}", key);
                if (key.isAcceptable()) {
                    final ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                    final SocketChannel sc = channel.accept();
                    log.debug("sc ..{}", sc);
                    sc.configureBlocking(false);
                    final ByteBuffer buffer = ByteBuffer.allocate(16); //attachment
                    //将一个ByteBuffer作为附件关联到selectKey上
                    final SelectionKey scKey = sc.register(selector, 0, buffer);
                    scKey.interestOps(SelectionKey.OP_READ);

                } else if (key.isReadable()) {
                    try {
                        final SocketChannel channel = (SocketChannel) key.channel();
                        final ByteBuffer buffer = (ByteBuffer) key.attachment();
                        final int len = channel.read(buffer);//如果是正常断开，read的方法返回值是-1
                        if (len == -1) {
                            key.cancel();
                        } else {
                            if (len > 0) {
                                split(buffer);
                                if (buffer.position() == buffer.limit()) {
                                    final ByteBuffer newBuf = ByteBuffer.allocate(buffer.capacity() * 2);
                                    buffer.flip();
                                    newBuf.put(buffer);
                                    key.attach(newBuf);
                                }
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        key.cancel();//因为客户端断开了，因此需要将key取消（从selector的keys集合中真正删除key）
                    }
                }
                //处理key时，要从selectKeys集合中删除
                iterator.remove();
                //key.cancel();//事件取消
            }

        }

    }

    private static void split(ByteBuffer buf) {
        buf.flip();
        for (int i = 0; i < buf.limit(); i++) {
            if (buf.get(i) == '\n') {
                int length = i - buf.position() + 1;
                final ByteBuffer targetBuf = ByteBuffer.allocate(length);
                for (int j = 0; j < length; j++) {
                    targetBuf.put(buf.get());
                }

                debugAll(targetBuf);
            }
        }
        buf.compact();
    }
}
